/**
 * 24点生成器，对随机生成的四个数找出满足四则运算结果为24（或者是其他数）的串---参考答案       
 *              
 */
class TwentyFourGenerator{
  /**
   * 
   * @param {Number} maxArg 限制随机生成四个数中的最大数
   * @param {Number} targetNum 四则运算后的计算结果
   */
  constructor(maxArg,targetNum){
    this.maxArg = maxArg
    this.targetNum = targetNum
    //随机生成的四个数
    this.randomNumArray = new Array()
    //满足四个数四则运算得到24点的所有可能
    this.resultArray = new Array()
    this.bestAnswer = ""
  }

  setMaxArg(maxArg){
    this.maxArg = maxArg;
  }
  /**
   * 生成四个随机数
   */
  generateRandomNumber(){
    this.randomNumArray = []
    for(let i =0;i<4;i++){
      this.randomNumArray.push(Math.floor(Math.random()*this.maxArg+1)) 
    }
  }
  /**
   * 得到运算结果为24点的串作为参考答案。
   */
  getResult(){


  }
  /**
   * 
   * @param {Number} arg1 常数1
   * @param {Number} arg2 常数2
   * @param {String} computeType 运算符
   */
  arithmetic(arg1,arg2,computeType){
    let result = 0;
    switch(computeType){
      case "+": return result = arg1+arg2;break;
      case "-": return result = arg1-arg2;break;
      case "x": return result = arg1*arg2;break;
      case "÷": return result = arg1/arg2;break;
    }
  }
  /**
   * 得到满足运算结果为target的四则运算表达式
   * 1.四个数排列组合 4! = 24 种
   * 2.四个数使用三个运算符，运算符四种 4*4*4 = 64种
   * 3.确定运算顺序共五种 ，表达式使用逆波兰式
   *                a b c d -> ab/abc/abcd   ab+c+d+
   *                        -> ab/cd/abcd    ab+cd++
   *                        -> bc/abc/abcd   abc++d+
   *                        -> bc/bcd/abcd   abc+d++
   *                        -> cd/bcd/abcd   abcd+++
   * 4.将逆波兰式转换为中缀表达式，并计算结果是否为24，如果是则添加到resultArray
   */
  generate(){
    this.resultArray=[]
    let operatorArray = ["+","-","x","÷"]
    //第一步随机数排列组合
    let numArray = new Array();
    // this.randomNumArray.forEach(w=>{
    //   this.randomNumArray.forEach(x=>{
    //     if(x!=w){
    //       this.randomNumArray.forEach(y=>{
    //         if(y!=x && y!=w){
    //           this.randomNumArray.forEach(z=>{
    //             if(z!=x && z!=w && z!=y){
    //               let num = [w,x,y,z]
    //               numArray.push(num)
    //             }
    //           })
    //         }
    //       })
    //     }
    //   })
    // })
    for(let i=0;i<this.randomNumArray.length;i++){
      for(let j=0;j<this.randomNumArray.length;j++){
        if(i!=j){
          for(let k=0;k<this.randomNumArray.length;k++){
            if(k!=i && k!=j){
              for(let m=0;m<this.randomNumArray.length;m++){
                if(m!=i && m!=j && m!=k){
                  let num = [this.randomNumArray[i],this.randomNumArray[j],this.randomNumArray[k],this.randomNumArray[m]]
                  numArray.push(num)
                }
              }
            }
          }
        }
      }
    }
    //第二步
    let operatorCombinArray = new Array()
      // operatorArray.forEach(x=>{
      //     operatorArray.forEach(y=>{
      //         operatorArray.forEach(z=>{
      //             let operator = [x,y,z]
      //             operatorCombinArray.push(operator)
      //         })
      //     })
      // })

      for(let i=0;i<operatorArray.length;i++){
        for(let j=0;j<operatorArray.length;j++){
          for(let k=0;k<operatorArray.length;k++){
            let operator = [operatorArray[i],operatorArray[j],operatorArray[k]]
            operatorCombinArray.push(operator)
          }
        }
      }
    
    //  console.log(numArray.length)
    //第三步 随机数和运算符的组合
    let numAndOperatorArray = new Array()
    // numArray.forEach(x=>{
    //   operatorCombinArray.forEach(y=>{
    //     numAndOperatorArray.push(x.concat(y))
    //   })
    // })
    for(let i=0;i<numArray.length;i++){
      for(let j=0;j<operatorCombinArray.length;j++){
        numAndOperatorArray.push(numArray[i].concat(operatorCombinArray[j]))
      }
    }
    // console.log(numAndOperatorArray.length)
    //第四步 生成逆波兰式
    for(let i=0;i<numAndOperatorArray.length;i++){
      let x = numAndOperatorArray[i]
    // numAndOperatorArray.forEach(x=>{
      let polandArray = new Array();
      //4.1 ab+c+d+
      let polandOne = new Array()
      polandOne.push(x[0])
      polandOne.push(x[1])
      polandOne.push(x[4])
      polandOne.push(x[2])
      polandOne.push(x[5])
      polandOne.push(x[3])
      polandOne.push(x[6])
      polandArray.push(polandOne)
      // console.log(polandOne)
      //4.2 ab+cd++
      let polandTwo = new Array();
      polandTwo.push(x[0])
      polandTwo.push(x[1])
      polandTwo.push(x[4])
      polandTwo.push(x[2])
      polandTwo.push(x[3])
      polandTwo.push(x[5])
      polandTwo.push(x[6])
      polandArray.push(polandTwo)
      //4.3 abc++d+
      let polandThree = new Array()
      polandThree.push(x[0])
      polandThree.push(x[1])
      polandThree.push(x[2])
      polandThree.push(x[4])
      polandThree.push(x[5])
      polandThree.push(x[3])
      polandThree.push(x[6])
      polandArray.push(polandThree)
      
      //4.4 abc+d++
      let polandFour = new Array()
      polandFour.push(x[0])
      polandFour.push(x[1])
      polandFour.push(x[2])
      polandFour.push(x[4])
      polandFour.push(x[3])
      polandFour.push(x[5])
      polandFour.push(x[6])
      polandArray.push(polandFour)
      //4.5 abcd+++
      let polandFive = new Array();
      polandFive.push(x[0])
      polandFive.push(x[1])
      polandFive.push(x[2])
      polandFive.push(x[3])
      polandFive.push(x[4])
      polandFive.push(x[5])
      polandFive.push(x[6])
      polandArray.push(polandFive)

    //由逆波兰式计算结果，选出最佳推荐答案（尽少的出现小数和负数）
    // 最佳推荐答案算法：给每一个答案末尾加一个分数，默认100分，出现负数或者小数减5分，同时出现减十分，最终选出得分最高的result
      for(let j=0;j<polandArray.length;j++){
        let polandExpress = polandArray[j]
      // polandArray.forEach(polandExpress=>{
        //初始分数
        let score = 100;
        //深拷贝后面使用
        let tempExpress =  JSON.parse(JSON.stringify(polandExpress))
        //运算栈j
        let stack = new Array()
        while(polandExpress.length>0){
          let nowStr = polandExpress.shift()
          stack.push(nowStr)
          //栈顶元素
          let topStr = stack[stack.length-1]
          if(operatorArray.indexOf(topStr)>-1){
            //弹出栈顶三个元素运算
            let operator = stack.pop()
            let arg2 = stack.pop()
            let arg1 = stack.pop()
            let tempResult = this.arithmetic(arg1,arg2,operator)
            if(tempResult!=parseInt(tempResult)){
              score-=5
            }
            if(tempResult<0){
              score-=5
            }
            stack.push(tempResult)
          }
        }

        if(stack[0]==this.targetNum){
          tempExpress.push(score)
          this.resultArray.push(tempExpress)
        }
      // })
      }
    // })
    }
    
  }
  /**
   * 1.循环generateRandomNumber，generate直至resultArray不为空
   * 从所有结果中选出最佳答案（尽可能多的使用加减少用乘除）
   */
  getBestAnswer(){
   
    let hasBest = false;
    let bestAnswerArray = new Array()
    do{
      this.generateRandomNumber()
      this.generate()

      if(this.resultArray.length!=0){
        // this.resultArray.forEach(x=>{
        //   if(x.indexOf(100)>0){
        //     hasBest = true
        //     bestAnswer = x
        //     return
        //   }
        // })
        for(let i=0;i<this.resultArray.length;i++){
          let x = this.resultArray[i]
            if(x.indexOf(100)>0){
            hasBest = true
            bestAnswerArray = x
            break;
          }
        }
      }
    }while(this.resultArray.length==0 && hasBest==false)
    //弹出分数
    bestAnswerArray.pop()
    this.bestAnswer = this.suffixToInfix(bestAnswerArray)
  }
  /**
   * 后缀表达式改为中缀表达式
   * @param {Array} suffixArray 
   */
  suffixToInfix(suffixArray){
    let operatorArray = ["+","-","x","÷"]
    //运算栈
    let stack = new Array()
    while(suffixArray.length>0){
      let nowStr = suffixArray.shift()
      stack.push(nowStr)
      //栈顶元素
      let topStr = stack[stack.length-1]
      if(operatorArray.indexOf(topStr)>-1){
        let resultStr = ""
        //弹出栈顶三个元素运算
        let operator = stack.pop()
        let arg2 = stack.pop()
        let arg1 = stack.pop()
        resultStr = "("+arg1+operator+arg2+")"
        // console.log(resultStr)
        stack.push(resultStr)
      }
    }
    return stack[0]
  }
}
let twentyFourGenerator = new TwentyFourGenerator(10,24)
module.exports = {
  twentyFourGenerator : twentyFourGenerator
}
